#if DEBUG_VERSION
if (!dafos) {
  throw new Error("Dafos namespace not found!");
}
#endif

#if STATETAB

dafos.onStateTabActivated = function() {
  if (dafos.statetab == null) {
    dafos.statetab = new dafos.StateTab(document.getElementById("statetab"), dafos.ui);
  }
  TRACK("tab/state");
  RESIZE();
};


/**
 * Constructor
 */
dafos.StateTab = function(parent, ui) {
  LOG("[StateTab]");
  var callbacks = {
      "ondetailsclicked": dafos.bind(this.traversePersonTree, this)
  };
  this.gadgetui = ui;
  this.ui = new dafos.StateTabUI(parent, callbacks);
  
  this.person_fields_ = [];
  for (var field in opensocial.Person.Field) {
    if (opensocial.Person.Field.hasOwnProperty(field)) {
#ifdef HI5
      if (field != "JOBS" && field != "SCHOOLS") { 
#endif
      this.person_fields_.push(field);
#ifdef HI5
      }
#endif
    }
  };
  
  var me = this;
  var id_input = e34.$("statetab-fetchbyid-input");
  var params = new quikos.PeopleParams().addFields(this.person_fields_);
    
  e34.$("statetab-fetchviewer-button").addOnClickHandler(function () {
    new quikos().startRequest()
        .fetchPerson(quikos.id.VIEWER, "person", params)
        .fetchData(quikos.idspec.VIEWER, "data", "*")
        .sendRequest(dafos.bind(me.onPersonData, me, "Displaying the viewer:"));
  });
  
  e34.$("statetab-fetchowner-button").addOnClickHandler(function () {
    new quikos().startRequest()
        .fetchPerson(quikos.id.OWNER, "person", params)
        .fetchData(quikos.idspec.OWNER, "data", "*")
        .sendRequest(dafos.bind(me.onPersonData, me, "Displaying the owner:"));
  });
  
  e34.$("statetab-fetchviewerfriends-button").addOnClickHandler(
      this.closeGetPeople(
          quikos.idspec.VIEWER_FRIENDS,"Displaying the viewer's friends:", 
          0, dafos.StateTab.PAGE_SIZE));
  
  e34.$("statetab-fetchownerfriends-button").addOnClickHandler(
      this.closeGetPeople(
          quikos.idspec.OWNER_FRIENDS,"Displaying the owner's friends:", 
          0, dafos.StateTab.PAGE_SIZE));
          
  e34.$("statetab-fetchbyid-button").addOnClickHandler(function () {
      var id = id_input.getValue();
      new quikos().startRequest()
          .fetchPerson(id, "person", params)
          .fetchData(quikos.idspec.personById(id), "data", "*")
          .sendRequest(dafos.bind(me.onPersonData, me, "Displaying user #" + id + ":"));
  });
  
#ifndef OPENSOCIAL_0_7
  e34.$("statetab-fetchfriendsbyid-button").addOnClickHandler(function () {
      var id = id_input.getValue();
      me.closeGetPeople(
          quikos.idspec.friendsById(id),
          "Displaying friends of user #" + id + ":", 
          0, 
          dafos.StateTab.PAGE_SIZE)();
  });    
#endif

};

dafos.StateTab.PAGE_SIZE = 20;
dafos.StateTab.INDENT_SIZE = 15;
dafos.StateTab.FIELD_OBJECT = {
  "Person Fields"                            : "opensocial.Person.Field",
  "opensocial.Person.Field.ADDRESSES"        : "opensocial.Address.Field",
  "opensocial.Person.Field.CURRENT_LOCATION" : "opensocial.Address.Field",
  "opensocial.Person.Field.EMAILS"           : "opensocial.Email.Field",
  "opensocial.Person.Field.JOBS"             : "opensocial.Organization.Field",
  "opensocial.Person.Field.PHONE_NUMBERS"    : "opensocial.Phone.Field",
  "opensocial.Person.Field.SCHOOLS"          : "opensocial.Organization.Field",
  "opensocial.Person.Field.NAME"             : "opensocial.Name.Field",
  "opensocial.Person.Field.URLS"             : "opensocial.Url.Field"
};
                         
dafos.StateTab.prototype.closeGetPeople = function(idspec, title, first, max) {
  var me = this;
  
  return function () {
    var params = new quikos.PeopleParams()
        .setFirst(first)
        .setMax(max)
        .addFields(me.person_fields_);
    
    new quikos().startRequest()
        .fetchPeople(idspec, "people", params)
        .fetchData(idspec, "data", "*")
        .sendRequest(dafos.bind(me.onPeopleData, me, idspec, title));
  }
};

dafos.StateTab.prototype.onPersonData = function(title, data, quikos) {
  LOG("[StateTab.onPersonData]", "data:", data, "quikos:", quikos);
  this.ui.clearOutput();
  this.ui.renderTitle(title);
  if (data["person"]) {
    var persistence_data = data.data && data.data[data["person"].getId()] || {};
    this.ui.renderPerson(data["person"], persistence_data);
  } else {
    if (quikos.hadError("person")) {
      this.gadgetui.setError(quikos.getFullErrorMessage("person"));
    }
    this.ui.renderPerson(this.ui.getFakePerson(
      "unknown",
      "This record was not found",
      "@server.deploy.base@/img/noperson.gif"));
  }
  gadgets.window.adjustHeight();
};

dafos.StateTab.prototype.onPeopleData = function(idspec, title, data, quikos) {
  this.ui.clearOutput();
  this.ui.renderTitle(title);
  
  if (data["people"] && data["people"].size() > 0) { 
    var buttons = this.ui.renderPagingControls(
        data["people"].getOffset(),
        data["people"].size(),
        data["people"].getTotalSize());
        
    //TODO: This button callback handling is a bit gross.  Clean this up a bit.
    if (buttons["prev"]) {
      var offset = 
          Math.max(data["people"].getOffset() - dafos.StateTab.PAGE_SIZE, 0);
      
      var handler = 
          this.closeGetPeople(idspec, title, offset, dafos.StateTab.PAGE_SIZE);
      
      buttons["prev"].addOnClickHandler(handler);
    };
    
    if (buttons["next"]) {
      var offset = data["people"].getOffset() + dafos.StateTab.PAGE_SIZE;
      
      var handler = 
          this.closeGetPeople(idspec, title, offset, dafos.StateTab.PAGE_SIZE);
      
      buttons["next"].addOnClickHandler(handler);
    };
    
    var me = this;
    data["people"].each(function (person) {
      var persistence_data = data.data && data.data[person.getId()] || {};
      me.ui.renderPerson(person, persistence_data);
    });
  } else {
    if (quikos.hadError("people")) {
      this.gadgetui.setError(quikos.getFullErrorMessage("people"));
    }
    this.ui.renderPerson(this.ui.getFakePerson(
      "unknown",
      "These records were not found",
      "@server.deploy.base@/img/nopeople.gif")); 
  }
  gadgets.window.adjustHeight();
};


dafos.StateTab.prototype.traversePersonTree = function(id, person, data) {
  this.ui.hideShowDetailsButton(id);

  var person_queue = [{ 
      "key": "Person Fields", 
      "modifier" : "",
      "data": person, 
      "ns": "opensocial.Person.Field",
      "depth": 0
  }];
  
  var callback = dafos.bind(this.ui.renderPersonField, this.ui, id);
  this.traverseObject(person_queue, callback);
  
  var data_queue = [{
      "key": "Persistence Data",
      "modifier" : "",
      "data" : data,
      "ns": "",
      "depth": 0
  }]
  this.traverseObject(data_queue, callback);
  
  gadgets.window.adjustHeight();
};

dafos.StateTab.prototype.queueSort = function(a, b) {
  var a_key = a.key + a.modifier;
  var b_key = b.key + b.modifier;
  if (a_key == b_key) {
    return 0;
  }
  return (a_key > b_key) ? -1 : 1;
};

dafos.StateTab.prototype.traverseObject = function(queue, callback) {
  while (queue.length > 0) {
    var p = queue.pop();
    
    //If the object is a base type
    if (e34.isString(p.data) ||
        e34.isBoolean(p.data)) {
      callback(p.key + p.modifier, p.data, p.depth);

    //If the object is a number
    } else if (e34.isNumber(p.data)) {
      callback(p.key + p.modifier, p.data.toString(), p.depth);
      
    //If the object is a boolean
    } else if (e34.isBoolean(p.data)) {
      callback(p.key + p.modifier, p.data, p.depth);
      
    //If the object is an enum
    } else if (p.data.getDisplayValue) {
      callback(p.key + p.modifier, "&nbsp;", p.depth);
      callback("opensocial.Enum.getDisplayValue()", p.data.getDisplayValue(), p.depth + 1);
      callback("opensocial.Enum.getKey()", p.data.getKey(), p.depth + 1);
    
    //If the object is an array
    } else if (e34.isArray(p.data)) {
      //callback(, "&nbsp;", p.depth);
      var items = [];
      for (var i = 0, len = p.data.length; i < len; i++) {
        var item = p.data[i]
        var obj = { 
          "key": p.key,
          "modifier": " [" + i + "]", 
          "data": item, 
          "ns": p.ns, 
          "depth": p.depth };
        items.push(obj); 
      }
      items.sort(this.queueSort);
      while (items.length > 0) {
        queue.push(items.shift());
      }
    
    //If the object is an opensocial type object
    } else if (p.data.getField) {
      var fields = this.getFieldsForObject_(p.key);
      if (fields) {
        callback(p.key + p.modifier, "&nbsp;", p.depth);
      }
      var namespace = dafos.StateTab.FIELD_OBJECT[p.key];
      var depth = p.depth + 1;
      var items = [];
      for (var name in fields) {
        //LOG("  ", name, fields[name]);
        var data = p.data.getField(fields[name]);
        var key = namespace + "." + name; 
        if (data != undefined) {
          var obj = { 
              "key": key, 
              "modifier": "",
              "data": data, 
              "ns": namespace, 
              "depth": depth 
          };
          //LOG("pushing", obj);
          items.push(obj);
        }
      }
      items.sort(this.queueSort);
      while (items.length > 0) {
        queue.push(items.shift());
      }
      
    //If the object is a generic object
    } else if (e34.isObject(p.data)) {
      callback(p.key + p.modifier, "&nbsp;", p.depth);
      for (var key in p.data) {
        if (p.data.hasOwnProperty(key)) {
          var data = p.data[key];
          if (data != undefined) {
            var obj = { 
                "key": key, 
                "modifier": "",
                "data": data, 
                "ns": namespace, 
                "depth": p.depth + 1 };
            queue.push(obj);
          }
        }
      } 
         
    //All other cases
    } else {
      callback(p.key + p.modifier, "Unknown", p.depth);
    }
  }
  gadgets.window.adjustHeight();
};

dafos.StateTab.prototype.resolveNamespace_ = function(ns) {
  var parts = ns.split(".");
  var pointer = window;
  for (var i = 0, part; part = parts[i]; i++) {
    pointer = pointer[part] || {};
  }
  return pointer;
};

dafos.StateTab.prototype.getFieldsForObject_ = function(key) {
  if (dafos.StateTab.FIELD_OBJECT[key] != undefined) {
    return this.resolveNamespace_(dafos.StateTab.FIELD_OBJECT[key]);
  } else {
    var keys = {};
    return keys;
  }
}


/**
 * Constructor
 */
dafos.StateTabUI = function(parent, callbacks) {
  LOG("[StateTabUI]");
  this.dom_parent_ = parent;
  this.callbacks_ = callbacks;
  this.field_row_template_ = e34.$("statetab-fields-row-template")
      .removeFromParent();
  this.field_table_template_ = e34.$("statetab-fields-template")
      .removeFromParent();
  this.person_template_ = e34.$("statetab-person-template")
      .removeFromParent();

  this.dom_output_ = e34.$("statetab-output");
  this.render();
  this.rendered_people_ = 0;
  this.row_parents_ = {};
  this.row_counts_ = {};
  this.render();
};

dafos.StateTabUI.prototype.render = function() {
  e34.$("statetab").removeClass("hidden");
};

dafos.StateTabUI.prototype.renderTitle = function(title) {
  var title = e34.renderTemplate("<h2>@title@</h2>", {
    "title": title
  });
  title.setParent(this.dom_output_);
};

dafos.StateTabUI.prototype.renderPagingControls = function(offset, size, total) {
  var text = e34.renderTemplate("<p>Showing @start@ to @end@ of @total@. </p>", {
    "start": offset + 1,
    "end": size + offset,
    "total": total
  });
  
  //TODO: This is ugly - figure out a better mvc method for this.
  var buttons = {};
  if (offset > 0) {
    var prev_button = e34.renderTemplate("<span><a href='javascript:void(0);'>Previous</a> </span>", {});
    prev_button.setParent(text);
    buttons["prev"] = prev_button;
  }
  if (size + offset < total) {
    var next_button = e34.renderTemplate("<span><a href='javascript:void(0);'>Next</a> </span>", {});
    next_button.setParent(text);
    buttons["next"] = next_button;
  }
  text.setParent(this.dom_output_);
  return buttons;
};

dafos.StateTabUI.prototype.clearOutput = function() {
  this.dom_output_.removeAllChildren();
  this.rendered_people_ = 0;
  this.row_parents_ = {};
  this.row_counts_ = {};
};

dafos.StateTabUI.prototype.renderPerson = function(person, opt_data) {
  LOG("[StateTabUI.renderPerson]", "person:", person, opt_data);
  
  if (person) {
    var id = ++this.rendered_people_;
    var classname = (id % 2 == 0) ? "odd" : "even";
  

    var thumbnail = person.getField("thumbnailUrl") || 
                    "@server.deploy.base@/img/nophoto.gif";
    var template = e34.renderTemplate(this.person_template_, {
      "id": id,
      "classname": classname,
      "person_displayname": person.getDisplayName(),
      "person_id": person.getId()
    });     
    
    template.$T("img")[0].getElement().src = thumbnail;
    template.setParent(this.dom_output_);
    
    var button_showmore = template.$("statetab-details-button-" + id);
  
    if (person.isFakePerson) {
      button_showmore.hide();
    } else {
      var callback = dafos.bind(this.callbacks_.ondetailsclicked, this, id, person, opt_data);
      button_showmore.addOnClickHandler(callback);
      var table = e34.renderTemplate(this.field_table_template_)
          .setParent(button_showmore.getParentElement())
          .addClass("fieldstable")
          .hide();
  
      this.row_parents_[id] = table;
      this.row_counts_[id] = 0;
    }
  
    gadgets.window.adjustHeight();
  }
};

dafos.StateTabUI.prototype.getFakePerson = function(id, name, img) {
  return {
    getDisplayName: function() { return name; },
    getId: function() { return id; },
    getField: function(field) {
      switch (field) {
        case "thumbnailUrl":
          return img;
      }
    },
    isFakePerson: true
  };
};

dafos.StateTabUI.prototype.renderPersonField = function(id, key, value, depth) {  
  var parent_table = this.row_parents_[id];
  
  var rowid = this.row_counts_[id]++;
  var classname = (depth == 0) ? "headerrow" : "fieldrow";
  var padding_str = "";
  for (var i = 0; i < depth; i++) {
    padding_str += "\t";
  }
  
  var row = e34.renderTemplate(this.field_row_template_, {
    "key": gadgets.util.escapeString(padding_str + key),
    "value": gadgets.util.escapeString(value || ""),
    "classname": classname
  }).setParent(parent_table.$T("tbody")[0]);
  
  var cell = row.$T("td")[0];
};

dafos.StateTabUI.prototype.hideShowDetailsButton = function(id) {
  e34.$("statetab-details-button-" + id).hide();
  this.row_parents_[id].show();
};
#endif

